
import ucigame.*;
import java.util.Random;
import java.util.ArrayList;

//this class includes enemy projectiles, to make
//things simpler
public class Monster extends Sprite
{
	int type;
	int startFrame;
	int currentFrame;
	int attackRate; //in frames
	int health;
	
	boolean gravity;
	boolean left;
	boolean right;
	boolean directionChange;
	boolean flicker;
	boolean dead;
	
	Sprite playerSprite;
	int screenH = 1279;
	int screenW = 300;
	
	Random rng;
	ArrayList<Monster> spawns;
	
	public Monster(int t, int sf, Image img, int x, int y)
	{
		super(x, y);
		
		type = t;
		startFrame = sf;
		currentFrame = sf;
		directionChange = false;
		flicker = false;
		dead = false;
		
		rng = new Random();
		spawns = new ArrayList<Monster>();
		
		attackRate = 0; //set to 0 here as a default for
						//monsters with no attacks (monsters
						//that only move, etc)
		
		//defaults for switch statement
		health = 1;
		gravity = false;
		left = true;
		right = false;
		
		switch(type)
		{
			case 0:
				//dimensions: 15, 17
				this.addFrames(img,
						2, 3,
						22, 3,
						42, 3,
						61, 3,
						80, 3,
						100, 3,
						120, 3,
						138, 3);
				this.framerate(20);
				
				gravity = true;
				health = 3;
				break;
			case 1:
				//dimensions: 15, 14
				this.addFrames(img,
						1, 34,
						22, 34,
						45, 34);
				this.framerate(10);
				
				health = 1;
				break;
			case 2:
				//dimensions: 28, 30
				this.addFrames(img,
						7, 167,
						44, 167);
				this.framerate(20);
				
				health = 4;
				break;
			
			//bosses (uses numbers >= 1000)
			case 1000:
				//dimensions: 28, 50
				this.addFrames(img, 
						32, 4,
						89, 4,
						144, 4,
						205, 10,
						255, 12);
				this.framerate(20);
				gravity = true;
				health = 10;
				break;
				
			default: //uses goomba/case 1
				this.addFrames(img,
						2, 3,
						22, 3,
						42, 3,
						61, 3,
						80, 3,
						100, 3,
						120, 3,
						138, 3);
				this.framerate(20);
				break;
		}
	}

	public int getStartFrame()
	{
		return startFrame;
	}
	
	public int getAttackRate()
	{
		return attackRate;
	}
	
	public void setAttackRate(int ar)
	{
		attackRate = ar;
	}
	
	public int getHealth()
	{
		return health;
	}
	
	public boolean isFlicker()
	{
		return flicker;
	}
	
	public void setFlicker(boolean f)
	{
		flicker = f;
	}
	
	public boolean isDead()
	{
		return dead;
	}
	
	public boolean isGravity()
	{
		return gravity;
	}
	
	public void setCurrentFrame(int cf)
	{
		currentFrame = cf;
	}
	
	public int getCurrentFrame()
	{
		return currentFrame;
	}
	
	public void givePlayer(Sprite p)
	{
		playerSprite = p;
	}
	
	public void changeDirection()
	{
		left = !left;
		right = !right;
		directionChange = !directionChange;
	}
	
	public void draw()
	{
		if(directionChange)
		{
			this.flipHorizontal();
		}
		super.draw();
	}
	
	//following methods depend on monster type
	//////////////////////////////////////////
	
	public void move()
	{
		switch(type)
		{
			case 0:
				standardGroundMove();
				break;
			case 1:
				flyingMove();
				break;
			case 2:
				//stays still
				break;

			case 1000:
				standardGroundMove();
				break;
		}
	}
	
	public void handleFloorCollision(Sprite f)
	{
		switch(type)
		{
			case 0:
				standardFloorCollision(f);
				break;
			case 1:
				//this enemy goes through floors/walls
				break;
			case 2:
				//this enemy goes through floors/walls
				break;
			
			case 1000:
				standardFloorCollision(f);
				break;
		}
	}
	
	//Handles collision with player.
	//Returns damage dealt to player
	public int handlePlayerCollision(Sprite p)
	{
		int damage = 0;
		
		switch(type)
		{
			case 0:
				damage = standardPlayerCollision(p);
				break;
			case 1:
				damage = standardPlayerCollision(p);
				damage = 2;
				break;
			case 2:
				damage = standardPlayerCollision(p);
				damage = 3;
				break;

			case 1000:
				damage = standardPlayerCollision(p);
				break;
		}
		
		return damage;
	}
	
	public boolean handleBulletCollision(Bullet b)
	{
		boolean killed = false;
		
		switch(type)
		{
			case 0:
				killed = standardBulletCollision(b);
				break;
			case 1:
				killed = standardBulletCollision(b);
				break;
			case 2:
				killed = standardBulletCollision(b);
				break;
			
			case 1000:
				killed = standardBulletCollision(b);
				break;
		}
		
		dead = killed;
		return killed;
	}
	
	public void drawSpawns()
	{
		for(int s = 0; s < spawns.size(); s++)
		{
			spawns.get(s).draw();
		}
	}
	
	public void moveSpawns()
	{
		for(int s = 0; s < spawns.size(); s++)
		{
			spawns.get(s).move();
		}
	}
	
	//the following are helpers for the types
	/////////////////////////////////////////
	
	//Standard (Type 0)
	///////////////////
	private void standardGroundMove()
	{
		if(left)
		{
			this.motion(-4, 0);
		}
		else if(right)
		{
			this.motion(4, 0);
		}
		super.move();
	}
	
	private void standardFloorCollision(Sprite f)
	{
		if(this.y() <= (f.y() - this.height()))
		{
			this.nextY(f.y() - this.height());
		}
		else
		{
			if(this.y() >= (f.y() + f.height()))
			{
				this.nextY(f.y() + f.height());
			}
			else
			{
				this.nextX(this.x());
				this.changeDirection();
			}
		}
	}
	
	private int standardPlayerCollision(Sprite p)
	{
		return 1;
	}
	
	//returns true if monster is killed (health <= 0)
	private boolean standardBulletCollision(Bullet b)
	{	
		switch(b.getType())
		{
			case 0:
				health--;
				break;
			case 1:
				health = health - 2;
				break;
		}
		
		return (health <= 0);
	}
	
	
	//Flying (Type 1)
	/////////////////
	private void flyingMove()
	{
		if(left)
		{
			this.motion(-3, 0);
		}
		else if(right)
		{
			this.motion(3, 0);
		}
		super.move();
	}
	
	
	//Spawn methods
	///////////////
	
	private void spawnProjectile(int num)
	{
		//spawns.add(new Monster(num, num, null, num, num));  //add
	}
}
